package com.yuanxin.baidumap;


import android.Manifest;
import android.util.Log;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.SystemClock;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.yanzhenjie.permission.Action;
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.Permission;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * Created by yiyang on 16/4/11.
 */
public class ReactMapLocationModule extends ReactContextBaseJavaModule {

    private static String TAG = ReactMapLocationModule.class.getSimpleName();
    private LocationClient mClient;
    private  final ReactApplicationContext reactContext;

    @Override
    public String getName() {
        return "BaiduLocationService";
    }

    BaiduLocationListener.ReactLocationCallback mLocationCallback = new BaiduLocationListener.ReactLocationCallback() {
        @Override
        public void onSuccess(BDLocation bdLocation) {
            getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                    .emit("baiduLocationDidChange", locationToMap(bdLocation));
        }

        @Override
        public void onFailure(BDLocation bdLocation) {
            emitError("unable to locate, locType = " + bdLocation.getLocType());
        }
    };

    public ReactMapLocationModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext=reactContext;
    }

    @ReactMethod
    public void getCurrentPosition(ReadableMap options, final Callback success, final Callback error) {
        // Log.e(TAG, "getCurrentPosition---" + options);
        AndPermission.with(getReactApplicationContext())
                .permission(Permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
                .onGranted(new Action() {
                    @Override
                    public void onAction(List<String> permissions) {
                        LocationClientOption option = defaultOption();
                        LocationClient client = new LocationClient(getReactApplicationContext().getApplicationContext(), option);
                        //TODO：移除使用最后一次定位数据的逻辑，每次都重新定位，确保定位准确。
                        //        BDLocation lastLocation = client.getLastKnownLocation();
                        //        if (lastLocation != null) {
                        //            Double locationTime = convertLocationTime(lastLocation);
                        //            if (locationTime != null && (SystemClock.currentTimeMillis() - locationTime < 1000)) {
                        //                success.invoke(locationToMap(lastLocation));
                        //                return;
                        //            }
                        //        }
                        new SingleUpdateRequest(client, success, error).invoke();
                    }
                })
                .onDenied(new Action() {
                    @Override
                    public void onAction(List<String> permissions) {
                        for (int i = 0; i < permissions.size(); i++) {
                            // Log.e("MapView", "拒绝了权限：" + permissions.get(i));
                        }
                        WritableMap map = Arguments.createMap();
                        map.putString("error","no permissions");
//                        error.invoke(map);
                    }
                }).start();


    }

    @ReactMethod
    public void getCurrentPosition2() {
         Log.e(TAG, "getCurrentPosition---");
        AndPermission.with(getReactApplicationContext())
                .permission(Permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
                .onGranted(new Action() {
                    @Override
                    public void onAction(List<String> permissions) {
                        LocationClientOption option = defaultOption();
                        LocationClient client = new LocationClient(getReactApplicationContext().getApplicationContext(), option);
                        //TODO：移除使用最后一次定位数据的逻辑，每次都重新定位，确保定位准确。
                        //        BDLocation lastLocation = client.getLastKnownLocation();
                        //        if (lastLocation != null) {
                        //            Double locationTime = convertLocationTime(lastLocation);
                        //            if (locationTime != null && (SystemClock.currentTimeMillis() - locationTime < 1000)) {
                        //                success.invoke(locationToMap(lastLocation));
                        //                return;
                        //            }
                        //        }
                        new SingleUpdateRequest2(client,reactContext).invoke();
                    }
                })
                .onDenied(new Action() {
                    @Override
                    public void onAction(List<String> permissions) {
                        for (int i = 0; i < permissions.size(); i++) {
                            // Log.e("MapView", "拒绝了权限：" + permissions.get(i));
                        }
                        WritableMap map = Arguments.createMap();
                        map.putString("error","no permissions");
                        map.putBoolean("authorization",false);
//                        promise.reject("error", "no permissions");
                        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                                .emit("position",map);
                    }
                }).start();


    }

    @ReactMethod
    public void startObserving(ReadableMap options) {
        LocationClientOption option = defaultOption();

        if (mClient == null) {
            mClient = new LocationClient(getReactApplicationContext().getApplicationContext(), option);
            new BaiduLocationListener(mClient, mLocationCallback);
        } else {
            mClient.setLocOption(option);
        }

        if (!mClient.isStarted()) {
            AndPermission.with(getReactApplicationContext())
                    .permission(Permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
                    .onGranted(new Action() {
                        @Override
                        public void onAction(List<String> permissions) {
                            try {
                                mClient.start();
                            } catch (Exception ex) {
                                ex.printStackTrace();
                            }
                        }
                    })
                    .onDenied(new Action() {
                        @Override
                        public void onAction(List<String> permissions) {
                            for (int i = 0; i < permissions.size(); i++) {
                                // Log.e("MapView", "拒绝了权限：" + permissions.get(i));
                            }
                        }
                    }).start();

        }
    }

    @ReactMethod
    public void stopObserving() {
        if (mClient != null) {
            mClient.stop();
        }
    }

    public static LocationClientOption defaultOption() {
        LocationClientOption option = new LocationClientOption();
        option.setCoorType("bd09ll");
        option.setOpenGps(true);
        option.setScanSpan(1000);
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        option.setIsNeedAddress(true);
//        option.setIsNeedLocationPoiList(true);
        option.disableCache(true);//禁止启用缓存定位
        return option;
    }

    private static WritableMap locationToMap(BDLocation location) {
        if (location == null) {
            return null;
        }
        WritableMap map = Arguments.createMap();
        WritableMap coords = Arguments.createMap();
        coords.putDouble("latitude", location.getLatitude());
        coords.putDouble("longitude", location.getLongitude());
        coords.putString("address", location.getAddrStr());
        coords.putDouble("accuracy", location.getRadius());
        coords.putDouble("altitude", location.getAltitude());
        coords.putString("city",location.getCity());
        coords.putInt("altitudeAccuracy", location.getGpsAccuracyStatus());
        coords.putDouble("heading", location.getDirection());
        coords.putDouble("speed", location.getSpeed());
        map.putMap("coords", coords);
        map.putBoolean("authorization",true);
        map.putDouble("timestamp", convertLocationTime(location));
        return map;
    }

    private void emitError(String error) {
        getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("kkLocationError", error);
    }

    public static Double convertLocationTime(BDLocation location) {
        if (location == null || location.getTime() == null || location.getTime().length() == 0) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Double timestamp = null;
        try {
            Date date = format.parse(location.getTime());
            timestamp = (double) date.getTime();

        } catch (Exception e) {

        }
        return timestamp;
    }

    private static class SingleUpdateRequest {
        private final Callback mSuccess;
        private final Callback mError;
        private final LocationClient mClient;

        private final BDAbstractLocationListener mListenr;


        private SingleUpdateRequest(LocationClient client, Callback success, Callback error) {
            this.mClient = client;
            mSuccess = success;
            mError = error;
            mListenr = new BDAbstractLocationListener() {

                @Override
                public void onReceiveLocation(BDLocation bdLocation) {
                    if (bdLocation == null) {
                        // Log.e("RNBaidumap", "receivedLocation is null!");
                        return;
                    }

                    // Log.i("RNBaidumap", "received location: " + bdLocation.getLocType() + ", " + bdLocation.getLatitude() + ", " + bdLocation.getLongitude());
                    int locateType = bdLocation.getLocType();
                    if (locateType == BDLocation.TypeGpsLocation
                            || locateType == BDLocation.TypeNetWorkLocation
                        //|| locateType == BDLocation.TypeOffLineLocation //离线定位不刷新，暂时屏蔽
                            ) {
                        mSuccess.invoke(locationToMap(bdLocation));
                        mClient.unRegisterLocationListener(mListenr);
                        mClient.stop();
                    }
//                    离线定位不刷新，暂时屏蔽
//                    else {
//                        mError.invoke("定位失败: " + bdLocation.getLocType());
//                        mClient.unRegisterLocationListener(mListenr);
//                        mClient.stop();
//                    }
                }
            };
            this.mClient.registerLocationListener(mListenr);
        }

        public void invoke() {
            if (mClient == null) {
                return;
            }
            if (mClient.isStarted()) {
                mClient.requestLocation();
            } else {
                mClient.start();
            }
        }
    }
    private static class SingleUpdateRequest2 {
        private final LocationClient mClient;
        private final BDAbstractLocationListener mListenr;


        private SingleUpdateRequest2(LocationClient client, final ReactApplicationContext reactContext) {
            this.mClient = client;
            mListenr = new BDAbstractLocationListener() {

                @Override
                public void onReceiveLocation(BDLocation bdLocation) {
                    if (bdLocation == null) {
                         //Log.e("RNBaidumap", "receivedLocation is null!");
                        return;
                    }

                     //Log.i("RNBaidumap", "received location: " + bdLocation.getLocType() + ", " + bdLocation.getLatitude() + ", " + bdLocation.getLongitude());
                    int locateType = bdLocation.getLocType();
                    if (locateType == BDLocation.TypeGpsLocation
                            || locateType == BDLocation.TypeNetWorkLocation
                        //|| locateType == BDLocation.TypeOffLineLocation //离线定位不刷新，暂时屏蔽
                            ) {
                        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                                .emit("position",locationToMap(bdLocation));
                        mClient.unRegisterLocationListener(mListenr);
                        mClient.stop();
                    }
//                    离线定位不刷新，暂时屏蔽
//                    else {
//                        mError.invoke("定位失败: " + bdLocation.getLocType());
//                        mClient.unRegisterLocationListener(mListenr);
//                        mClient.stop();
//                    }
                }
            };
            this.mClient.registerLocationListener(mListenr);
        }

        public void invoke() {
            if (mClient == null) {
                return;
            }
            if (mClient.isStarted()) {
                mClient.requestLocation();
            } else {
                mClient.start();
            }
        }
    }
}
